package application;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Button;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.text.Text;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.fxml.FXML;

public class UIController {
	@FXML private Text QueryImgAddress;
	@FXML private Text AverageF1;
	@FXML private PieChart PieChartRecall;
	@FXML private PieChart PieChartPrecision;
	@FXML private TableView<Result> SearchResultTable;
	@FXML private TableColumn rank;
	@FXML private TableColumn images;
	@FXML private TableColumn similarity;
	@FXML private TableColumn file_name;
	@FXML private ImageView QueryImageView;
	@FXML private ImageView ImagePreview;
	@FXML private Button GroundTruthChooser;
	@FXML private Button DataSetChooser;
	@FXML private Text F1;
	
	private BufferedImage bufferedQueryImg;
	private String queryImageName;
	private ObservableList<Result> data = FXCollections.observableArrayList();
	private String docPath;
	private File docFolder;
	private File truthFolder;
	private File queryFolder;
	private ObservableList<? extends Integer> lst;
	private ObservableList<PieChart.Data> pieChartDataRecall = FXCollections.observableArrayList();
	private ObservableList<PieChart.Data> pieChartDataPrecision = FXCollections.observableArrayList(); 
	ImageSearchLogic  logic;
	
	@FXML protected void AddQueryImage(MouseEvent event) {
		logic = new ImageSearchLogic();
		Stage stage = (Stage) QueryImgAddress.getScene().getWindow();
		FileChooser fileChooser = new FileChooser();
		fileChooser.setTitle("Open Resource File");
		File file = fileChooser.showOpenDialog(stage);
		if (file!=null) {
			QueryImgAddress.setText(file.getAbsolutePath());
			queryImageName = file.getName();
			FileInputStream fis = null;
			try {
				fis = new FileInputStream(file);
			} catch (FileNotFoundException e) {
			}
			Image img = new Image(fis);
    		QueryImageView.setImage(img);
    		
    		try {
				bufferedQueryImg = ImageIO.read(file);
			} catch (IOException e) {
			}
		}
	}
	
	@FXML protected void AddDataSet(MouseEvent event) {
		Stage stage = (Stage) DataSetChooser.getScene().getWindow();
		DirectoryChooser fc = new DirectoryChooser();
    	fc.setTitle("Open File");
    	File file = fc.showDialog(stage);
    	if (file!=null) {
    		docPath = file.getAbsolutePath();
    		docFolder = file;
    		DataSetChooser.setText("Chosen");
    	}
	}
	
	@FXML protected void AddGroundTruth(MouseEvent event) {
		Stage stage = (Stage) GroundTruthChooser.getScene().getWindow();
		DirectoryChooser fc = new DirectoryChooser();
    	fc.setTitle("Open File");
    	File file = fc.showDialog(stage);
    	if (file!=null) {
    		truthFolder = file;
    		GroundTruthChooser.setText("Chosen");
    	}
	}
	
	@FXML protected void LoadAllQuery(MouseEvent event){
		logic = new ImageSearchLogic();
		Stage stage = (Stage) DataSetChooser.getScene().getWindow();
		DirectoryChooser fc = new DirectoryChooser();
    	fc.setTitle("Open File");
    	File file = fc.showDialog(stage);
    	if (file!=null) {
    		queryFolder = file;
    		double averageF1 = 0;
    		List<SearchOutCome> searchResult;
    		ObservableList<Result> resultList = FXCollections.observableArrayList();
    		File[] listOfFiles = queryFolder.listFiles();
    		
    		for(int j=0;j<listOfFiles.length;j++){
    			BufferedImage brImage = null;
				try {
					brImage = ImageIO.read(listOfFiles[j]);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
    			String queryImage = listOfFiles[j].getName();
	    		resultList.clear();
	    		searchResult = logic.searchLibrary(brImage, new ArrayList<SearchOutCome>());
	    		for (int i = 0; i<20;i++){
	    			String fileName = searchResult.get(i).fileName;
	    			resultList.add(new Result(0,0,null, docPath + "\\"+fileName));
	    		}
	    		int count = calculateCorrectCount(queryImage, resultList);
	    		averageF1 += 2*(double)(count/20.0)*(count/20.0)/(count/10.0);
    		}
    		System.out.println(averageF1/20);
    		AverageF1.setText(new Double(averageF1/20).toString());
    	}
	}
	
	@FXML protected void Search(MouseEvent event) throws FileNotFoundException {
		rank.setCellValueFactory(new PropertyValueFactory<Result, String>("rank"));
		similarity.setCellValueFactory(new PropertyValueFactory<Result, String>("similarity"));
		images.setCellValueFactory(new PropertyValueFactory<Result, ImageView>("image"));
		file_name.setCellValueFactory(new PropertyValueFactory<Result, String>("name"));
		
		data.clear();
		//Add in data here
		//Search logic
		List<SearchOutCome> searchResult = logic.searchLibrary(bufferedQueryImg,new ArrayList<SearchOutCome>());
		
		for (int i = 0; i<20;i++){
			String fileName = searchResult.get(i).fileName;
			double similarity = searchResult.get(i).score;
			Image image = new Image(new FileInputStream(new File(docPath + "\\"+fileName)));
			
			data.add(new Result(i+1,similarity,image, docPath + "\\"+fileName));
		}
		
		
		SearchResultTable.setItems(data);
		
		SearchResultTable.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
		SearchResultTable.getSelectionModel().getSelectedIndices().addListener(new ListChangeListener<Integer>(){
    		public void onChanged(Change<? extends Integer>change){
    			lst = change.getList();
    		}
		});
		SearchResultTable.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent t) {
                if (SearchResultTable.getSelectionModel().getSelectedItem() != null) {
                   Image img = SearchResultTable.getSelectionModel().getSelectedItem().getImage().getImage();
                   ImagePreview.setImage(img);
                }
            }
        });
	}
	
	@FXML protected void Analyze(MouseEvent event) {
		
		String fileName = queryImageName;
		int count = calculateCorrectCount(fileName, data);
		drawPieChart(count);
	}
	


	@FXML protected void Feedback(MouseEvent event) throws FileNotFoundException {

		ArrayList<String> feedBackFileList = new ArrayList<String>();
		System.out.println("lst size "+ lst.size());
		if(lst.size()>0){
			for (int i =0;i < lst.size();i++){
				String fileName = data.get(lst.get(i)).getFileName();
				fileName = fileName.substring(0,fileName.length()-4);
				fileName = fileName.concat(".txt");
				System.out.println(fileName);
				feedBackFileList.add(fileName);
			}
			
			rank.setCellValueFactory(new PropertyValueFactory<Result, String>("rank"));
			similarity.setCellValueFactory(new PropertyValueFactory<Result, String>("similarity"));
			images.setCellValueFactory(new PropertyValueFactory<Result, ImageView>("image"));
			file_name.setCellValueFactory(new PropertyValueFactory<Result, String>("name"));
			
			data.clear();
			
			//Do the feedback here
			ArrayList<SearchOutCome>searchResult = logic.feedback(bufferedQueryImg, feedBackFileList);
			
			for (int i = 0; i<20;i++){
				String fileName = searchResult.get(i).fileName;
				double similarity = searchResult.get(i).score;
				Image image = new Image(new FileInputStream(new File(docPath + "\\"+fileName)));
				
				data.add(new Result(i+1,similarity,image, docPath + "\\"+fileName));
			}
			
			
			SearchResultTable.setItems(data);
		}
	}
	
	
	@FXML protected void Index(MouseEvent event) {
		logic = new ImageSearchLogic();
		try {
    		logic.indexImage(docFolder);
    		//logic.indexTag(docFolder);
    		logic.luceneIndex(docFolder);
		}
		catch (Exception e){
			
		}
	}
	
	
	private int calculateCorrectCount(String fileName,ObservableList<Result> data){
		fileName = fileName.substring(0, fileName.indexOf("."));
		fileName += "_GroundTruth.txt";
		
		String path = truthFolder.getAbsolutePath();
		File file = new File(path+"\\"+fileName);
		ArrayList<String> matchedFileNames = new ArrayList<String>();
		
		try {
			BufferedReader output = new BufferedReader(new FileReader(file));
			String line;
			
			int index = 1;
			while ((line=output.readLine())!=null){
				if(Integer.parseInt(line)==1){
					matchedFileNames.add(new Integer(index).toString()+".jpg");
				}
				index++;
			}
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		int count = 0;
		if (matchedFileNames.size()!=0){
			for(int i=0;i<matchedFileNames.size();i++){
				for(int j=0;j<data.size();j++){
					String name = data.get(j).getFileName();
					name = name.substring(name.lastIndexOf("\\")+1, name.length());
					if (matchedFileNames.get(i).equals(name))
						count++;
				}
			}
		}
		return count;
	}
	
	private void drawPieChart(int correctCount) {
		pieChartDataRecall.clear();
		pieChartDataRecall.add(new PieChart.Data("Recall", correctCount));
		pieChartDataRecall.add(new PieChart.Data("Fail", (20-correctCount)));
		PieChartRecall.setData(pieChartDataRecall);
		
		pieChartDataPrecision.clear();
		pieChartDataPrecision.add(new PieChart.Data("Precision", correctCount));
		pieChartDataPrecision.add(new PieChart.Data("Fail", (20-correctCount)));
		PieChartPrecision.setData(pieChartDataPrecision);
		
		double f1 = 2*((double)(correctCount/20.0)*(correctCount/20.0)/(correctCount/10.0));
		F1.setText(new Double(f1).toString());
	}
	
	
	public class Result{
		SimpleStringProperty rank;
		SimpleStringProperty similarity;
		SimpleObjectProperty<ImageView> image;
		SimpleStringProperty name;
		private String fileName;
		
		Result(int rank, double similarity, Image img, String fileName) {
			this.rank = new SimpleStringProperty(Integer.toString(rank));
			this.similarity = new SimpleStringProperty(Double.toString(similarity));
			ImageView view = new ImageView(img);
			view.setFitHeight(50);
			view.setFitWidth(50);
			this.image = new SimpleObjectProperty<ImageView>(view);
			this.fileName = fileName;
			name = new SimpleStringProperty(fileName.substring(fileName.lastIndexOf("\\")+1, fileName.length()));

		}
		
    	public String getRank(){
    		return rank.get();
    	}
    	
    	public String getSimilarity(){
    		return similarity.get();
    	}
    	
    	public ImageView getImage(){
    		return (ImageView) image.get();
    	}
    	
    	public String getFileName(){
    		return fileName;
    	}
    	
    	public String getName(){
    		return name.get();
    	}
	}
}
